home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / vol6n10.arc / SLASHBAR.ASM < prev    next >
Assembly Source File  |  1987-05-11  |  41KB  |  1,365 lines

  1. ;======================================================================
  2. ;  SLASHBAR is a memory resident interpreter for files prepared by the
  3. ;  MAKEBAR utility.  Bar-menu Description Files (.BDF) are first prepared
  4. ;  to contain the keystrokes and prompts needed to perform the functions.
  5. ;  The .BDF file is then or compiled to a BAR file.  This
  6. ;  file is loaded on the command line.
  7. ;
  8. ;  Usage:  SLASHBAR  [path\]menuname [/n]
  9. ;    where /n is the size buffer to allocate.  /n is only valid for the
  10. ;    first load and is specified in bytes.  For obvious reasons it
  11. ;    should be as large as the largest .BAR file you will use < 60K.
  12. ;----------------------------------------------------------------------
  13. LO_MEM    SEGMENT AT 0000H
  14.         ORG    41AH
  15. BIOS_HEAD    DW    ?
  16. BIOS_TAIL    DW    ?
  17. BIOS_BUF    DW    16 DUP (?)
  18.  
  19. LO_MEM    ENDS
  20.  
  21. ;======================================================================
  22. CSEG    SEGMENT    PARA    PUBLIC    'CODE'
  23.         ORG    100H            ;COM file format
  24. STACK        LABEL    WORD            ;Use PSP as stack when res.
  25.  
  26.         ASSUME CS:CSEG,DS:CSEG,ES:CSEG,SS:CSEG
  27.  
  28. ;----------------------------------------------------------------------
  29. ;  Equates - substituted literally when assembled.
  30. ;----------------------------------------------------------------------
  31. CR        EQU    0DH            ;HEX for carriage return
  32. LF        EQU    0AH            ; and line feed
  33.                         ;ALT-RIGHT SHIFT-TILDE
  34. HOTKEY        EQU    35H            ;SCAN code activating key
  35. SHIFT_MASK    EQU    08H            ;Mask to pick out 'shifts'
  36.                         ;1000 = ALT     0100 = CTRL
  37.                         ;0010 = L.SHIFT 0001 = R SHIFT
  38.  
  39. NROW        EQU    4            ;Number of rows in the window
  40. NCOL        EQU    80            ;Number of cols in the window
  41. BOX_COL        EQU    0            ;Left col of window on screen
  42. BOX_ROW        EQU    0            ;Top of screen
  43. BW_ATTR        EQU    7007H            ;Monochrome window
  44. CO_ATTR        EQU    0417H            ;Color window
  45.  
  46. SPACE        EQU    20H            ;Equivalents for some keys
  47. ESC_KEY        EQU    1BH
  48. BS_KEY        EQU    08H
  49. TAB_KEY        EQU    09H
  50. RIGHT_ARROW    EQU    4DH
  51. LEFT_ARROW    EQU    4BH
  52. HOME_KEY    EQU    47H
  53. END_KEY        EQU    4FH
  54.  
  55. MAX_CMD_VAL    EQU    10            ;Use for error checking
  56.  
  57. ;----------------------------------------------------------------------
  58. ;  COM file entry point is at 100h
  59. ;----------------------------------------------------------------------
  60. ENTPT:        JMP    INITIALIZE        ;Perform initialization
  61.  
  62. COPYRIGHT  DB  "SlashBar 1.1 (c) 1987, Ziff-Davis Publishing Corp."
  63.        DB  CR,LF,"$",1AH
  64.        DB  "Robert L. Hummel"
  65.  
  66. ;----------------------------------------------------------------------
  67. ;  Data used by INT_9 procedure.  Other data precedes other procedures.
  68. ;----------------------------------------------------------------------
  69. OLD_INT_9    DD    0            ;Storage for old vectors
  70. OLD_INT_16    DD    0
  71. OLD_INT_21    DD    0
  72. DOS_FLAG    DD    0            ;Address of dos critical flag
  73.  
  74. ACTIVE        DB    0            ;Inside pop-up
  75. LO_FN_FLAG    DB    0            ;When inside Int 21h
  76.  
  77. DISPLAY_PAGE    DB    0            ;Used by screen save
  78. CURSOR_POS    DW    0            ; to restore info
  79.  
  80. OLD_SS        DW    0            ;To save stack
  81. OLD_SP        DW    0            ; during switching
  82.  
  83. ;======================================================================
  84. ;  New Interrupt 9 routine. Invoked each key-press.
  85. ;  Test to see if our key combination has been typed.
  86. ;----------------------------------------------------------------------
  87. INT_9        PROC    FAR
  88.         ASSUME    CS:CSEG, DS:NOTHING, ES:NOTHING, SS:NOTHING
  89.                         ;(Flags saved by INT)
  90.         STI                ;Allow interrupts
  91.         PUSH    AX            ;Save used register
  92.  
  93.         IN    AL,60H            ;Get key scan code
  94.         CMP    AL,HOTKEY        ;Check if hot-key
  95.         JNE    PROCESS_KEY        ;If not, continue on.
  96.  
  97.         MOV    AH,2            ;Get shift status fn
  98.         INT    16H            ;Thru BIOS
  99.  
  100.         AND    AL,0FH            ;Test only for 'shift' keys
  101.         CMP    AL,SHIFT_MASK        ;If they match our combination
  102.         JE    OUR_KEY            ;then is our signal
  103. PROCESS_KEY:
  104.         POP    AX            ;Restore register
  105.         JMP    DWORD PTR CS:OLD_INT_9    ;Process key as normal
  106. OUR_KEY:
  107. ;----------------------------------------------------------------------
  108. ;  Reset the keyboard interrupt controller (forget the key stroke)
  109. ;----------------------------------------------------------------------
  110.         IN    AL,61H            ;These instructions reset
  111.         MOV    AH,AL            ; the keyboard.
  112.         OR    AL,80H
  113.         OUT    61H,AL
  114.         MOV    AL,AH
  115.         JMP    SHORT $+2        ;I/O delay
  116.         OUT    61H,AL
  117.         CLI                ;Disable interrupts and
  118.         MOV    AL,20H            ;reset the int controller
  119.         OUT    20H,AL
  120.         STI                ;Allow interrupts
  121.  
  122. ;----------------------------------------------------------------------
  123. ;    If program is already active, or DOS is busy, simply return.
  124. ;----------------------------------------------------------------------
  125.         CMP    CS:ACTIVE,0        ;If already active, can't call
  126.         JNE    RETURN_A
  127.  
  128.         MOV    AX,CS:KEY_PTR        ;If head of our key buffer
  129.         CMP    AX,CS:KEY_TAKE        ; isn't = tail
  130.         JNE    RETURN_A        ; we still have keys to lose
  131.  
  132.         INC    CS:ACTIVE        ;Turns off BIOS flag in INT_16
  133.         MOV    AH,1            ;If the BIOS key buffer
  134.         INT    16H            ; has keys in it
  135.         MOV    CS:ACTIVE,0
  136.         JNZ    RETURN_A        ; don't pop up
  137.  
  138.         PUSH    DS            ;Save used registers
  139.         PUSH    BX
  140.  
  141.         LDS    BX,CS:DOS_FLAG        ;If DOS critical flag is not
  142.         CMP    BYTE PTR [BX],0        ; busy
  143.         JE    INVOKE            ;We can pop up
  144.  
  145.         CMP    CS:LO_FN_FLAG,0        ;If busy from low function
  146.         JNE    INVOKE            ; go pop up
  147. RETURN_B:
  148.         POP    BX            ;Restore other registers
  149.         POP    DS
  150. RETURN_A:
  151.         POP    AX            ;Restore register
  152.         IRET                ;Go back where we came from
  153. INVOKE:
  154. ;----------------------------------------------------------------------
  155. ;  From the video mode, determine the box colors to use.
  156. ;----------------------------------------------------------------------
  157.         MOV    WORD PTR CS:NCLR,CO_ATTR ;Use color window
  158.         MOV    AH,0FH            ;Get current video mode fn
  159.         CALL    VIDEO            ;Thru BIOS
  160.         MOV    CS:DISPLAY_PAGE,BH    ;Save current page
  161.                         ;Valid video modes are:
  162.         CMP    AL,1            ;COLOR 40X25
  163.         JZ    MODE_OK
  164.         CMP    AL,3            ;COLOR 80x25
  165.         JE    MODE_OK
  166.  
  167.         MOV    WORD PTR CS:NCLR,BW_ATTR ;Default to mono window
  168.         CMP    AL,7            ;MONO 80x25
  169.         JE    MODE_OK
  170.         CMP    AL,2
  171.         JA    RETURN_B        ;Go back from whence we came
  172. MODE_OK:
  173. ;----------------------------------------------------------------------
  174. ;  If here, routine becomes active, save all other used registers.
  175. ;----------------------------------------------------------------------
  176.         MOV    CS:ACTIVE,1        ;Set flag to prevent re-entry
  177.  
  178.         PUSH    CX            ;Save all registers for return
  179.         PUSH    DX
  180.         PUSH    DI
  181.         PUSH    SI
  182.         PUSH    ES
  183.         PUSH    BP
  184.  
  185.         MOV    AX,CS            ;Put our CS into these regs
  186.         MOV    DS,AX            ;So we can find our data
  187.         MOV    ES,AX            ;And our string moves
  188.     ASSUME    DS:CSEG,ES:CSEG            ;Tell the Assembler
  189.         MOV    OLD_SS,SS        ;Swap stacks after all
  190.         MOV    OLD_SP,SP        ; registers are pushed
  191.         CLI                ;Turn off interrupts
  192.         MOV    SS,AX            ;Put our stack in place
  193.         MOV    SP,OFFSET STACK
  194.         STI                ;Interrupts on
  195.     ASSUME    SS:CSEG                ;Tell the Assembler
  196.  
  197. ;----------------------------------------------------------------------
  198. ;  Save the details of the current screen for later restoration.
  199. ;----------------------------------------------------------------------
  200.         MOV    AH,3            ;Get cursor position fn
  201.         CALL    VIDEO            ;Thru BIOS
  202.         MOV    CURSOR_POS,DX        ;Save position for
  203.                         ;restoration on exit
  204. ;----------------------------------------------------------------------
  205. ;  Save section of screen we will be writing over.
  206. ;----------------------------------------------------------------------
  207.         MOV    DI,OFFSET SCREEN_BUF    ;Destination for save
  208.         MOV    SI,0FFFFH        ;Switch for proc to save
  209.         CALL    SCREEN
  210.  
  211. ;----------------------------------------------------------------------
  212. ;  Perform specific function.
  213. ;----------------------------------------------------------------------
  214.         CALL    CLR_BOX            ;Draw box & border
  215.         CALL    MENU_TIME
  216. CANCEL:
  217. ;----------------------------------------------------------------------
  218. ;  Restore the screen to original state.
  219. ;----------------------------------------------------------------------
  220.         MOV    SI,OFFSET SCREEN_BUF
  221.         CALL    SCREEN
  222.  
  223.         MOV    AH,2            ;Set Cursor position fn
  224.         MOV    DX,CURSOR_POS        ;Restore old cursor position
  225.         CALL    VIDEO            ;Thru BIOS
  226.  
  227.         MOV    AX,OLD_SS        ;Restore previous stack
  228.         MOV    BX,OLD_SP
  229.         CLI                ;No interrupts
  230.         MOV    SS,AX
  231.         MOV    SP,BX
  232.         STI                ;Allow interrupts
  233.  
  234.         MOV    ACTIVE,0        ;Turn off active flag
  235.  
  236.         POP    BP            ;Restore all used registers
  237.         POP    ES
  238.         POP    SI
  239.         POP    DI
  240.         POP    DX
  241.         POP    CX
  242.         POP    BX
  243.         POP    DS
  244.         POP    AX
  245.  
  246.         IRET                ;Interrupt gets IRET
  247. INT_9    ENDP
  248.  
  249. ;======================================================================
  250. ;  BIOS Video Interrupt.  Some older versions of the BIOS destroy the
  251. ;  BP register inside the video routine.
  252. ;----------------------------------------------------------------------
  253. VIDEO        PROC    NEAR
  254.  
  255.         PUSH    BP            ;Preserve register
  256.         INT    10H            ;Call to BIOS
  257.         POP    BP            ;Restore
  258.         RET
  259.  
  260. VIDEO        ENDP
  261.  
  262. ;======================================================================
  263. ;  Perform the screen save/restore.
  264. ;  SAVE:    SI=FFFF, DI=buffer address
  265. ;  RESTORE: SI=buffer address, DI=don't care
  266. ;----------------------------------------------------------------------
  267. SCREEN        PROC    NEAR
  268.         ASSUME    CS:CSEG, DS:CSEG, ES:CSEG, SS:NOTHING
  269.  
  270.         CLD                ;String moves forward
  271.         MOV    BH,DISPLAY_PAGE        ;Just to be sure, reset page
  272.  
  273.         MOV    CX,NROW            ;Row loop
  274.         MOV    ROW,BOX_ROW        ;Init row pointer
  275. ROW_LOOP:
  276.         PUSH    CX            ;Prepare for...
  277.         MOV    CX,NCOL            ;...column loop
  278.         MOV    COL,BOX_COL        ;Column Pointer
  279. COL_LOOP:
  280.         CMP    SI,0FFFFH        ;SI =FFFF if SAVE
  281.         JE    DO_SAVE
  282.                         ;RESTORE
  283.         LODSW                ;AX <- [SI]
  284.                         ;AH=ATTR AL=CHAR
  285.         CALL    CRT_CHAR        ;Write char to screen
  286.         JMP    SHORT DO_LOOP
  287. DO_SAVE:
  288.         CALL    SET_CUR            ;Position cursor
  289.         MOV    AH,8            ;Get char & attribute fn
  290.         CALL    VIDEO            ;Thru BIOS
  291.         STOSW                ;[di+=2]=ax
  292. DO_LOOP:
  293.         INC    COL            ;Next column
  294.         LOOP    COL_LOOP        ;Close Inner loop
  295.  
  296.         POP    CX            ;Return to outer loop
  297.         INC    ROW            ;Next row
  298.         LOOP    ROW_LOOP        ;Close Outer loop
  299.         RET
  300.  
  301. SCREEN        ENDP
  302.  
  303. ;======================================================================
  304. ;  Clear a window (box) for our information on the screen.
  305. ;  Add a border for a nice touch.
  306. ;----------------------------------------------------------------------
  307. BOX_MSG        DB    BOX_COL+2,BOX_ROW,0B5H,"SlashBar 1.1",0C6H,0
  308. BOX_CHARS    DB    0C9H,0CDH,0BBH,0BAH,020H,0BAH,0C8H,0CDH,0BCH
  309.  
  310. CLR_BOX        PROC    NEAR
  311.  
  312.         MOV    AX,0600H        ;Scroll entire window fn
  313.         MOV    CH,BOX_ROW        ;Upper row
  314.         MOV    ROW,CH
  315.         MOV    CL,BOX_COL        ;Left column
  316.         MOV    DH,BOX_ROW + NROW - 1    ;Lower row
  317.         MOV    DL,BOX_COL + NCOL - 1    ;Right column
  318.         MOV    BH,NCLR            ;Window color
  319.         CALL    VIDEO            ;Thru BIOS
  320.  
  321.         MOV    BH,DISPLAY_PAGE        ;This page
  322.         MOV    AH,NCLR            ;This color
  323.         MOV    SI,OFFSET BOX_CHARS    ;Source of characters
  324.         MOV    DX,CX            ;Cursor from last call
  325.         MOV    CX,NROW            ;Number of rows to draw
  326. CB_1:
  327.         PUSH    CX            ;Save counter
  328.         MOV    COL,BOX_COL        ;Set column
  329.  
  330.         LODSB                ;Get leftmost char
  331.         CALL    CRT_CHAR        ; write to screen
  332.  
  333.         LODSB                ;Get middle char
  334.         MOV    CX,NCOL-2        ;Number copies to write
  335. CB_1A:
  336.         INC    COL            ;Next column
  337.         CALL    CRT_CHAR        ;Write char to screen
  338.         LOOP    CB_1A
  339.         INC    COL            ;Last column
  340.  
  341.         LODSB                ;Get rightmost char
  342.         CALL    CRT_CHAR        ; put on screen
  343.  
  344.         INC    ROW            ;Next row
  345.         POP    CX            ;Restore counter
  346.         CMP    CL,NROW            ;If written last row
  347.         JE    CB_2            ; put new chars
  348.         CMP    CL,2            ;If 2nd row
  349.         JE    CB_2            ; get new chars
  350.         SUB    SI,3            ;back up & repeat
  351. CB_2:
  352.         LOOP    CB_1            ;Loop each line
  353.  
  354.         MOV    SI,OFFSET BOX_MSG    ;Put program name
  355.         LODSW                ; at this row,col
  356.         MOV    CURSOR_LOC,AX
  357.         MOV    AH,NCLR            ; and this color
  358.         CALL    CRTZ            ; on screen
  359.         RET
  360.  
  361. CLR_BOX        ENDP
  362.  
  363. ;======================================================================
  364. ;  DOS Int 21h intercept.  Set flag while uninterruptable
  365. ;  The purpose of this procedure is to keep pop-up from taking control
  366. ;  of the machine when doing so would cause a crash.
  367. ;----------------------------------------------------------------------
  368. INT_21    PROC    FAR
  369.  
  370.         CMP    AH,0            ;If program is using DOS fn 0
  371.         JNE    CHECK
  372.         MOV    AH,4CH            ;Change it to 4Ch
  373. GO_DIRECT:
  374.         MOV    CS:LO_FN_FLAG,0        ;Not function 1-Ch
  375.         JMP    DWORD PTR CS:OLD_INT_21    ;Jump to original routine
  376. CHECK:
  377.         CMP    AH,0CH            ;DOS functions call under 0DH
  378.         JA    GO_DIRECT
  379.  
  380.         MOV    CS:LO_FN_FLAG,1        ; set this flag
  381.  
  382.         PUSHF                ;Simulate INT
  383.         CALL    DWORD PTR CS:OLD_INT_21    ; return here
  384.  
  385.         MOV    CS:LO_FN_FLAG,0        ;Turn off flag
  386.         RET    2            ;Return to INT source and
  387.                         ;discard old flags
  388. INT_21    ENDP
  389.  
  390. ;======================================================================
  391. ;  Int 16 intercept.  Use to feed keys to calling programs.
  392. ;----------------------------------------------------------------------
  393. LAST_CALL    DB    0        ;Remember last call so first or
  394.                     ;last key can be removed
  395. INT_16        PROC    FAR
  396.         ASSUME    CS:CSEG, DS:NOTHING, ES:NOTHING, SS:NOTHING
  397.  
  398.         CMP    CS:ACTIVE,0        ;Don't steal our own 'strokes!
  399.         JNE    GOTO_BIOS        ; get them thru BIOS
  400.  
  401.         CMP    AH,2            ;Ignore calls for shift status
  402.         JAE    DONT_SAVE
  403.         MOV    CS:LAST_CALL,AH
  404. DONT_SAVE:
  405.         STI                ;Interrupts on
  406.         PUSH    BX            ;Save used register
  407.  
  408.         MOV    BX,CS:KEY_TAKE        ;Pointer to next keystroke
  409.         CMP    BX,CS:KEY_PTR        ;If no keys in our buffer
  410.         JE    POP_GOTO_BIOS        ;Pass thru to BIOS
  411.  
  412.         CMP    AH,2            ;Request for shift status
  413.         JE    POP_GOTO_BIOS        ; goes thru BIOS always
  414.  
  415.         CMP    AH,0            ;Wait for key
  416.         JE    UNLOAD_KEY
  417.  
  418.         CMP    AL,1            ;Is key stroke ready?
  419.         JNE    POP_GOTO_BIOS        ;return NZ if key ready
  420.         OR    AL,AL            ;Generate a NZ
  421.         POP    BX
  422.         RET    2            ;Discard old flags
  423. UNLOAD_KEY:
  424.         MOV    BX,CS:KEY_TAKE        ;Get ptr to key in BX
  425.         MOV    AX,CS:[BX]        ;Get the key in AX
  426.         ADD    CS:KEY_TAKE,2        ;Move the ptr along
  427.  
  428.         POP    BX            ;Restore register
  429.         RET    2            ;Discard flags
  430.  
  431. POP_GOTO_BIOS:    POP    BX
  432. GOTO_BIOS:    JMP    DWORD PTR CS:OLD_INT_16
  433.  
  434. INT_16        ENDP
  435.  
  436. ;=======================================================================
  437. ; INTERPRETER - Read the contents of menu file and perform functions.
  438. ;  BP always contains the address of the start of the MENU buffer.
  439. ;    NOTE: THIS PROGRAM MAKES USE OF THE FACT THAT A .COM FILE
  440. ;          HAS CS=DS=ES=SS WHEN USING ADDRESSING WITH BP.
  441. ;          THEREFORE, SET UP A STACK USING THE CS SEGMENT.
  442. ;----------------------------------------------------------------------
  443. ;  Data structures.
  444. ;----------------------------------------------------------------------
  445. MENU_BASE    DW    FILE_DTA        ;Real address of offset 0
  446. DTA_SIZE    DW    4096            ;4k bytes by default
  447.  
  448. OPT_PTR        DW    0            ;Points to menu choice
  449. LEVEL        DW    0            ;Depth of menu tree
  450. NOPT        DW    0            ;Number options this menu
  451.  
  452. KEY_PTR        DW    KEYS            ;Points to next empty spot
  453. KEY_TAKE    DW    KEYS            ;Points to available char
  454.  
  455. CMD_TABLE    DW    ASK, CR_CMD, EXECUTE, INPUT, BAD_CMD, BAD_CMD
  456.         DW    BAD_CMD, TYPE_KEY, BAD_CMD, BAD_CMD, SEND
  457.  
  458. CURSOR_LOC    LABEL    WORD
  459. COL        DB    0            ;Display column
  460. ROW        DB    0            ;        row
  461.  
  462. NCLR        DB    07H            ;Normal video color
  463. RCLR        DB    70H            ;Reverse video color
  464.  
  465. ;=======================================================================
  466. ;  Prime the pointers with their initial values.
  467. ;----------------------------------------------------------------------
  468.     ASSUME    CS:CSEG,DS:CSEG,ES:CSEG,SS:CSEG
  469. MENU_TIME    PROC    NEAR
  470.  
  471.         CLD                ;String moves forward
  472.         XOR    DI,DI            ;DI = 0
  473.         MOV    AX,OFFSET KEYS        ;Initialize key buffer
  474.         MOV    KEY_PTR,AX
  475.         MOV    KEY_TAKE,AX
  476.         MOV    WORD PTR KEY_STK [DI],AX ;Starting KEY_PTR in stack
  477.         MOV    WORD PTR MENU_STK[DI],10 ;Offset into menu in stack
  478.         MOV    OPT_PTR,DI        ;Point to option 0
  479.         MOV    LEVEL,DI        ;We're at level 0
  480.         MOV    BP,MENU_BASE        ;Always points to menu base
  481.  
  482. ;----------------------------------------------------------------------
  483. ;  Put the PROGRAM name on the screen.
  484. ;----------------------------------------------------------------------
  485.         MOV    ROW,BOX_ROW        ;This row & column
  486.         MOV    COL,BOX_COL + NCOL - 12
  487.  
  488.         MOV    AH,NCLR            ;Normal color attribute
  489.         MOV    AL,0B5H            ;Char to write
  490.         CALL    CRT_CHAR        ;Write to screen
  491.         MOV    SI,BP            ;Point to program name
  492.  
  493.         MOV    CX,10            ;Maximum chars to write
  494. MT_1:
  495.         INC    COL            ;Next column
  496.         LODSB                ;Get char at DS:SI
  497.         OR    AL,AL            ;If 0
  498.         JZ    MT_2            ; end of string
  499.         CALL    CRT_CHAR        ; else, write it
  500.         LOOP    MT_1            ; and continue
  501. MT_2:
  502.         MOV    AL,0C6H            ;Close box
  503.         CALL    CRT_CHAR        ;Write char
  504.  
  505. ;----------------------------------------------------------------------
  506. ;  Menus are built from scratch.
  507. ;----------------------------------------------------------------------
  508. BUILD_MENU:
  509.         CALL    CLR_LINES        ;Clear inside of window
  510.  
  511.         MOV    DI,LEVEL        ;The menu level
  512.         SHL    DI,1            ; *2 for word access
  513.         MOV    AX,WORD PTR KEY_STK[DI]    ;Point to next key save point
  514.         MOV    KEY_PTR,AX        ; and put where it's used
  515.  
  516.         CALL    GET_MENU_HEAD        ;Offset of menu in DI
  517.         MOV    AX,[BP][DI]        ;Offset 0 has number opts
  518.         MOV    NOPT,AX
  519.  
  520.         CALL    WRITE_NAMES        ;Write the option names
  521.         CALL    WRITE_HELP        ;Write the help lines
  522.         CALL    GET_KEY            ;From user
  523.  
  524.         OR    AL,AL            ;AL = 0 If extended ascii
  525.         JNZ    ASCII_KEY
  526.  
  527.         CALL    MOVE_BAR        ;Could be left/right arrow
  528.         JMP    BUILD_MENU        ; or home/end
  529.  
  530. ;----------------------------------------------------------------------
  531. ;  ASCII key could be option letter, CR, ESC, or mistake.
  532. ;----------------------------------------------------------------------
  533. ASCII_KEY:
  534.         CALL    MAKE_UC            ;Make AL upper case
  535.         CALL    MATCH_KEY        ;Return NC if match and
  536.                         ; AL contains option #
  537.         JNC    MATCH_FOUND        ;No match found
  538.         CALL    BEEP
  539.         JMP    BUILD_MENU
  540. MATCH_FOUND:
  541.         CMP    AL,0FFH            ;AL=FF if ESC
  542.         JNE    READ_SCRIPT        ;Else, perform functions
  543.  
  544. ;----------------------------------------------------------------------
  545. ;  The ESC key was hit.  Back up one menu.  If at top menu, exit.
  546. ;  backing up removes any keystrokes put in by the current menu.
  547. ;----------------------------------------------------------------------
  548.         CMP    LEVEL,0            ;If at top menu
  549.         JE    CANCEL_MENU        ; leave
  550.         DEC    LEVEL            ;Back up
  551.         MOV    OPT_PTR,0
  552.         JMP    BUILD_MENU        ;Reconstruct display
  553. CANCEL_MENU:
  554.         MOV    KEY_PTR,OFFSET KEYS    ;Flush the buffer
  555.         RET                ;Return & Exit
  556.  
  557. ;----------------------------------------------------------------------
  558. ;  Interpret the option script.
  559. ;----------------------------------------------------------------------
  560. READ_SCRIPT:
  561.         CALL    GET_MENU_HEAD        ;Set DI = menu offset
  562.         MOV    AX,OPT_PTR        ;Each option takes 6 bytes
  563.         INC    AX            ;Extra 6 to point to token ptr
  564.         MOV    BL,6            ;3 words = 6 bytes
  565.         MUL    BL            ;Gives Additional offset in AX
  566.         ADD    DI,AX            ;DI is offset from menu head
  567.         MOV    SI,[BP][DI]        ;SI is offset to token
  568.         ADD    SI,BP            ;Real address
  569. GET_TOKEN:
  570.         LODSB                ;Get command token
  571.         MOV    BL,AL            ;Put in base register
  572.         CMP    BL,MAX_CMD_VAL
  573.         JA    BAD_CMD
  574.         SHL    BL,1            ;*2 for word access
  575.         XOR    BH,BH            ;Top is 0
  576.         JMP    CMD_TABLE[BX]        ;Execute based on value
  577. BAD_CMD:
  578.         ;If here, the .BAR file is bad, no recovery
  579.         ;Use the save exit as a top-level-escape
  580.         JMP    CANCEL_MENU
  581.  
  582. ;----------------------------------------------------------------------
  583. ;  ASK: Type the following string in the window
  584. ;  1st line is used for queries.
  585. ;----------------------------------------------------------------------
  586. ASK:
  587.         CALL    CLR_LINES        ;Clear inside of window
  588.         MOV    ROW,BOX_ROW + 1        ;Position the cursor
  589.         MOV    COL,BOX_COL + 2
  590.         MOV    AH,NCLR            ;Attribute to use
  591.         CALL    CRTZ            ;Copy chars till 0
  592.         JMP    GET_TOKEN        ;Get next instruction
  593.  
  594. ;----------------------------------------------------------------------
  595. ;  CR:    Put a CR in the buffer.
  596. ;----------------------------------------------------------------------
  597. CR_CMD:
  598.         MOV    AX,1C0DH        ;Put a carriage return
  599.         CALL    SAVE_KEY        ; in our key buffer
  600.         JMP    GET_TOKEN        ;Get next instruction
  601.  
  602. ;----------------------------------------------------------------------
  603. ;  EXECUTE: transfer control to a lower menu.
  604. ;----------------------------------------------------------------------
  605. EXECUTE:
  606.         INC    LEVEL            ;Next menu level
  607.         MOV    DI,LEVEL        ;Convert to index
  608.         CMP    DI,32            ;Maximum level of menus
  609.         JB    LEVEL_OK
  610. MENU_ERROR:
  611.         CALL    BEEP            ;Sound off!
  612.         JMP    CANCEL_MENU        ;And leave no trace
  613. LEVEL_OK:
  614.         SHL    DI,1            ;Index into tables
  615.         MOV    AX,KEY_PTR        ;Save current key_ptr
  616.         MOV    WORD PTR KEY_STK[DI],AX    ; to restore
  617.                         ;Following token is
  618.         LODSW                ; offset of new menu
  619.         MOV    WORD PTR MENU_STK[DI],AX ;Saved in "stack"
  620.         MOV    OPT_PTR,0
  621.         JMP    BUILD_MENU        ;Make new picture
  622.  
  623. ;----------------------------------------------------------------------
  624. ;  INPUT: Accept keystrokes from the user until CR.
  625. ;  2nd line is used for responses.
  626. ;----------------------------------------------------------------------
  627. INPUT:
  628.         CALL    BUFFERED_INPUT        ;Buffered input from console
  629.         JNC    GET_TOKEN        ;NC if all went ok
  630.         JMP    BUILD_MENU        ;Else rebuild menu
  631.  
  632. ;----------------------------------------------------------------------
  633. ;  TYPE: Put the following keystrokes into the key buffer.
  634. ;----------------------------------------------------------------------
  635. TYPE_KEY:
  636.         XOR    AH,AH            ;High byte is 0
  637.         LODSB                ;Get char in AL
  638.         OR    AL,AL            ;0 If end of sequence
  639.         JE    GET_TOKEN        ;Look for next command
  640.         CMP    AL,0FEH            ;Extended ascii switch
  641.         JNE    TYPE_1            ;Put char out as is
  642.         LODSB                ;Get extended code
  643.         CMP    AL,0FEH
  644.         JNE    TYPE_A
  645.         MOV    AX,1C0AH        ;Double FE FE = ctrl-enter
  646.         JMP    SHORT TYPE_2
  647. TYPE_A:
  648.         XCHG    AH,AL            ;Put code in high byte
  649.         JMP    SHORT TYPE_2        ;Stuff in buffer
  650. TYPE_1:
  651.         MOV    AH,1CH            ;Add the high bytes to
  652.         CMP    AL,CR            ; these selected keys
  653.         JE    TYPE_2            ; for compatibility
  654.  
  655.         MOV    AH,1
  656.         CMP    AL,ESC_KEY
  657.         JE    TYPE_2
  658.  
  659.         MOV    AH,0EH
  660.         CMP    AL,BS_KEY
  661.         JE    TYPE_2
  662.         CMP    AL,7FH
  663.         JE    TYPE_2
  664.  
  665.         INC    AH
  666.         CMP    AL,TAB_KEY
  667.         JE    TYPE_2
  668.         XOR    AH,AH
  669. TYPE_2:
  670.         CALL    SAVE_KEY        ;Put in KEYS buffer
  671.         JMP    TYPE_KEY        ;Try again
  672.  
  673. ;----------------------------------------------------------------------
  674. ;  SEND: Signal the end of the pop-up task.
  675. ;----------------------------------------------------------------------
  676. SEND:
  677.         MOV    BX,KEY_PTR        ;Pointer to next keystroke
  678.         CMP    BX,KEY_TAKE        ;If no keys in our buffer
  679.         JE    MENU_EXIT        ;No action needed
  680.  
  681.         CMP    LAST_CALL,0        ;If last call was wait-for-key
  682.         JE    USE_FIRST_KEY        ; stuff first key in buffer
  683.  
  684.         SUB    KEY_PTR,2        ;Point to last valid key
  685.         SUB    BX,2            ; move the pointer
  686.         JMP    SHORT REMOVE_KEY    ;Put in BIOS buffer
  687. USE_FIRST_KEY:
  688.         MOV    BX,KEY_TAKE        ;Remove first key
  689.         ADD    KEY_TAKE,2        ; advance pointer
  690. REMOVE_KEY:
  691.         MOV    CX,WORD PTR [BX]    ;Take out the LAST key
  692.  
  693.         PUSH    DS            ;Set up for low memory access
  694.         XOR    AX,AX
  695.         MOV    DS,AX
  696.     ASSUME    DS:LO_MEM
  697.         MOV    BX,OFFSET BIOS_HEAD    ;Start of bios key buffer
  698.  
  699.         CLI
  700.         MOV    WORD PTR [BX][0],001EH    ;Set the head
  701.         MOV    WORD PTR [BX][2],0020H    ;Set the Tail
  702.         MOV    WORD PTR [BX][4],CX    ;Put key in buffer
  703.         STI                ;Allow interrupts
  704.  
  705.         POP    DS            ;Restore the register
  706.     ASSUME    DS:CSEG                ;Tell the assembler
  707. MENU_EXIT:
  708.         RET
  709.         
  710. MENU_TIME    ENDP
  711.  
  712. ;======================================================================
  713. ;  Put offset of current menu_head into DI.  MENU_STK[LEVEL*2]
  714. ;  DI changed.  Other registers preserved.
  715. ;----------------------------------------------------------------------
  716. GET_MENU_HEAD    PROC    NEAR
  717.  
  718.         MOV    DI,LEVEL
  719.         SHL    DI,1
  720.         MOV    DI,WORD PTR MENU_STK[DI]
  721.         RET
  722.  
  723. GET_MENU_HEAD    ENDP
  724.  
  725. ;======================================================================
  726. ;  Write the current menu option choices to the screen.
  727. ;  AX,CX,DX,SI,DI changed.  Others preserved.
  728. ;----------------------------------------------------------------------
  729. WRITE_NAMES    PROC    NEAR
  730.  
  731.         MOV    ROW,BOX_ROW + 1        ;Position is one row down
  732.         MOV    COL,BOX_COL + 1        ;1 col over
  733.  
  734.         XOR    DX,DX            ;Option counter
  735.         MOV    CX,NOPT            ;Number of options this menu
  736.         CALL    GET_MENU_HEAD        ;In DI
  737. WN_1:
  738.         MOV    SI,[BP][DI][2]        ;SI is offset to name
  739.         ADD    SI,BP            ;SI points to name
  740. WN_2:
  741.         MOV    AH,NCLR            ;Normal color
  742.         MOV    AL,SPACE        ; with a space
  743.         INC    COL            ;Separate the names
  744.         CALL    CRT_CHAR
  745.         CMP    OPT_PTR,DX        ;Is this the current option
  746.         JNE    WN_3
  747.         MOV    AH,RCLR            ;Yes, use reverse color
  748. WN_3:
  749.         CALL    CRTZ            ;Copy until 0 to CRT
  750.         INC    DX            ;1 string complete
  751.         ADD    DI,6            ;Point to next ptr to name
  752.         LOOP    WN_1            ;Repeat for number of options
  753.         RET
  754.  
  755. WRITE_NAMES    ENDP
  756.  
  757. ;======================================================================
  758. ;  Write the help line for the current option below the names.
  759. ;  AX,BX,SI,DI changed.  Others preserved.
  760. ;----------------------------------------------------------------------
  761. WRITE_HELP    PROC    NEAR
  762.  
  763.         MOV    ROW,BOX_ROW + 2
  764.         MOV    COL,BOX_COL + 2
  765.  
  766.         CALL    GET_MENU_HEAD
  767.         MOV    AX,OPT_PTR        ;3 WORD offset for each opt
  768.         MOV    BL,6
  769.         MUL    BL            ;Gives Additional offset in AX
  770.         ADD    DI,AX            ;DI is ptr to offset of help
  771.         MOV    SI,[BP][DI][4]        ;SI is offset ptr to help
  772.         ADD    SI,BP
  773.         MOV    AH,NCLR            ;Normal color
  774.         CALL    CRTZ            ;Write string to CON
  775.         RET
  776.  
  777. WRITE_HELP    ENDP
  778.  
  779. ;======================================================================
  780. ;  Read a key from the console with no echo.
  781. ;  Return in AX.  Other registers preserved.
  782. ;----------------------------------------------------------------------
  783. GET_KEY        PROC    NEAR
  784.  
  785.         XOR    AH,AH            ;AH=0, wait for key
  786.         INT    16H             ; Thru BIOS
  787.         RET
  788.  
  789. GET_KEY        ENDP
  790.  
  791. ;======================================================================
  792. ;  Keystroke was extended ascii.  If left/right arrow, move opt_ptr.
  793. ;  BX,CX changed.  Other registers preserved.
  794. ;----------------------------------------------------------------------
  795. MOVE_BAR    PROC    NEAR
  796.  
  797.         MOV    BX,OPT_PTR        ;Current position
  798.         MOV    CX,NOPT            ;Maximum position is # opt
  799.         DEC    CX            ; minus one
  800.  
  801.         CMP    AH,RIGHT_ARROW        ;Move right
  802.         JNE    MB_1
  803.         INC    BX            ;Increase pointer
  804.         CMP    BX,CX            ;Past max?
  805.         JBE    MB_EXIT            ;No, exit
  806. MB_0:
  807.         XOR    BX,BX            ;Yes, reset to 0
  808.         JMP    SHORT MB_EXIT        ;and leave
  809. MB_1:
  810.         CMP    AH,LEFT_ARROW        ;Move left
  811.         JNE    MB_2
  812.         DEC    BX            ;Decrease pointer
  813.         JNS    MB_EXIT            ;Did it go negative?
  814. MB_1A:
  815.         MOV    BX,CX            ; yes, wrap to max
  816. MB_EXIT:
  817.         MOV    OPT_PTR,BX        ;Change pointer
  818.         RET                ;Leave
  819. MB_2:
  820.         CMP    AH,HOME_KEY        ;Home - go to 0
  821.         JE    MB_0
  822. MB_3:
  823.         CMP    AH,END_KEY        ;End - move to max
  824.         JE    MB_1A
  825.         CALL    BEEP
  826.         RET
  827.  
  828. MOVE_BAR    ENDP
  829.  
  830. ;======================================================================
  831. ;  Make the character in AL UPPER case.
  832. ;----------------------------------------------------------------------
  833. MAKE_UC        PROC    NEAR
  834.  
  835.         CMP    AL,'a'
  836.         JB    UC_1
  837.         CMP    AL,'z'
  838.         JA    UC_1
  839.         SUB    AL,20H
  840. UC_1:
  841.         RET
  842. MAKE_UC        ENDP
  843.  
  844. ;======================================================================
  845. ;  Search current names for matching first letter.  Return CY if no match.
  846. ;  If CR, choose current option, and return in AL.  If ESC, set AL=FF.
  847. ;  AX,BX,DX changed.  Others preserved.
  848. ;----------------------------------------------------------------------
  849. MATCH_KEY    PROC    NEAR
  850.  
  851.         CMP    AL,ESC_KEY        ;If ESC key hit
  852.         JNE    MK_0
  853.         MOV    AL,0FFH            ;Signal code
  854. MK_CLC:
  855.         CLC
  856. MK_EXIT:
  857.         RET                ;Return
  858. MK_0:
  859.         MOV    BX,AX            ;Save key
  860.         MOV    AX,OPT_PTR        ;Current option in AL
  861.         CMP    BL,CR            ;If CR struck
  862.         JE    MK_CLC            ;Return option number
  863.  
  864.         XOR    DX,DX            ;Option counter
  865.         MOV    CX,NOPT            ;Number of options this menu
  866.         CALL    GET_MENU_HEAD        ;In DI
  867. MK_1:
  868.         MOV    SI,[BP][DI][2]        ;SI is offset to name
  869.         ADD    SI,BP            ;SI points to opt name
  870.         LODSB                ;Get first letter in AL
  871.         CMP    AL,BL            ;Does key match?
  872.         JE    MK_2
  873.         INC    DX            ;Next option count
  874.         ADD    DI,6            ;Point to next ptr to name
  875.         LOOP    MK_1            ;Repeat for number of options
  876.         STC                ;Match not found
  877.         RET
  878. MK_2:
  879.         MOV    AX,DX            ;Put option match in AL
  880.         MOV    OPT_PTR,AX        ;And in pointer
  881.         JMP    MK_CLC
  882.  
  883. MATCH_KEY    ENDP
  884.  
  885. ;======================================================================
  886. ;  Copy an ASCIIZ string to the console at the current cursor location.
  887. ;  Cursor position is updated.  SI points to string and is moved.  AH
  888. ;  contains the attribute to used for the string.
  889. ;  AX,SI changed.  Other registers preserved.
  890. ;----------------------------------------------------------------------
  891. CRTZ        PROC    NEAR
  892. CRTZ_1:
  893.         LODSB                ;Get character
  894.         OR    AL,AL            ;If char is 0
  895.         JE    CRTZ_2            ; end of string
  896.         CALL    CRT_CHAR
  897.         INC    COL
  898.         JMP    CRTZ_1
  899. CRTZ_2:
  900.         RET
  901.  
  902. CRTZ        ENDP
  903.  
  904. ;======================================================================
  905. ;  Output the char in AL at the stored cursor position.
  906. ;  AH contains the attribute to be used.
  907. ;  Preserve all registers.
  908. ;----------------------------------------------------------------------
  909. CRT_CHAR    PROC    NEAR
  910.  
  911.         PUSH    AX            ;Save used registers
  912.         PUSH    BX
  913.         PUSH    CX
  914.  
  915.         CALL    SET_CUR            ;Set the cursor
  916.         MOV    CX,1            ;Write 1 char
  917.         MOV    BL,AH            ;Use this attribute
  918.         MOV    AH,9            ;Write char & attr
  919.         MOV    BH,DISPLAY_PAGE        ;This page
  920.         CALL    VIDEO            ; Thru BIOS
  921.  
  922.         POP    CX            ;Restore registers
  923.         POP    BX
  924.         POP    AX
  925.         RET
  926.  
  927. CRT_CHAR    ENDP
  928.  
  929. ;======================================================================
  930. ;  Clear the line in AL.  AX,BX,CX,DX destroyed.
  931. ;----------------------------------------------------------------------
  932. CLR_LINES    PROC    NEAR
  933.  
  934.         MOV    AX,0600H        ;Scroll screen Function
  935.         MOV    CH,BOX_ROW + 1        ;Upper row
  936.         MOV    DH,BOX_ROW + NROW - 2    ;Lower row
  937.         MOV    CL,BOX_COL + 1        ;Left col
  938.         MOV    DL,BOX_COL + NCOL - 2    ;Right col
  939.         MOV    BH,NCLR            ;Attribute
  940.         CALL    VIDEO            ;BIOS video
  941.         RET
  942.  
  943. CLR_LINES    ENDP
  944.  
  945. ;======================================================================
  946. ;  Position the cursor at ROW,COL.
  947. ;  Preserve all registers.
  948. ;----------------------------------------------------------------------
  949. SET_CUR        PROC    NEAR
  950.  
  951.         PUSH    AX            ;Save used registers
  952.         PUSH    BX
  953.         PUSH    DX
  954.  
  955.         MOV    DX,CURSOR_LOC        ;Load both row & col
  956.         MOV    AH,2            ;Move cursor fn
  957.         MOV    BH,DISPLAY_PAGE        ;Current page
  958.         CALL    VIDEO            ; Thru BIOS
  959.  
  960.         POP    DX            ;Restore registers
  961.         POP    BX
  962.         POP    AX
  963.         RET
  964.  
  965. SET_CUR        ENDP
  966.  
  967. ;======================================================================
  968. ;  Save the key in AX in KEYS buffer
  969. ;----------------------------------------------------------------------
  970. SAVE_KEY    PROC    NEAR
  971.  
  972.         PUSH    BX            ;Save used registers
  973.         PUSH    CX
  974.  
  975.         MOV    CX,KEY_PTR        ;Current pointer
  976.         MOV    BX,CX            ; also in BX
  977.         SUB    CX,OFFSET KEYS        ;Get # bytes
  978.         CMP    CX,512            ;More than allowed?
  979.         JE    SK_1            ;Simply ignore
  980.         MOV    [BX],AX            ;Store key
  981.         ADD    KEY_PTR,2        ;Move pointer
  982. SK_1:
  983.         POP    CX            ;Restore registers
  984.         POP    BX
  985.         RET
  986.  
  987. SAVE_KEY    ENDP
  988.  
  989. ;======================================================================
  990. ;  Read keys from the keyboard until a <CR>
  991. ;----------------------------------------------------------------------
  992. BUFFERED_INPUT    PROC    NEAR
  993.  
  994.         PUSH    AX            ;Save registers
  995.         PUSH    CX
  996.         PUSH    SI
  997. BUF_ERASE:
  998.         MOV    ROW,BOX_ROW + 2        ;Position cursor
  999.         MOV    COL,BOX_COL + 1
  1000.         CALL    SET_CUR
  1001.         MOV    AX,0A20H        ;Fill with blanks
  1002.         MOV    BH,DISPLAY_PAGE
  1003.         MOV    CX,NCOL - 2
  1004.         CALL    VIDEO            ; Thru BIOS
  1005.  
  1006.         MOV    SI,OFFSET INKEY_BUF    ;Point to start of buffer
  1007. BUF_1:
  1008.         MOV    CX,SI            ;Calculate buffer length
  1009.         SUB    CX,OFFSET INKEY_BUF    ; in CX
  1010.         CALL    SET_CUR            ;Position cursor
  1011.         CALL    GET_KEY            ;Read a key from the kbd
  1012.  
  1013.         OR    AL,AL            ;If low byte is 0
  1014.         JZ    BUF_1            ; not ascii
  1015.  
  1016.         CMP    AL,CR            ;Enter key
  1017.         JE    BUF_CR
  1018.  
  1019.         CMP    AL,ESC_KEY        ;Escape
  1020.         JE    BUF_ESC
  1021.  
  1022.         CMP    AL,BS_KEY        ;Backspace
  1023.         JE    BUF_BS
  1024.  
  1025.         CMP    CX,76 * 2        ;Maximum bytes allowed
  1026.         JA    BUF_2A
  1027. BUF_1A:
  1028.         MOV    [SI],AX            ;Save key in INKEY_BUF
  1029.         ADD    SI,2            ;Point to next entry
  1030. BUF_2:
  1031.         MOV    AH,NCLR
  1032.         CALL    CRT_CHAR        ;Write AL at row,col
  1033.         INC    COL            ;Next column
  1034.         JMP    BUF_1            ;Get more keys
  1035. BUF_BS:
  1036.         OR    CX,CX            ;Any keys in buf?
  1037.         JNZ    BUF_3
  1038. BUF_2A:
  1039.         CALL    BEEP
  1040.         JMP    BUF_1
  1041. BUF_3:
  1042.         SUB    SI,2            ;Remove key
  1043.         DEC    COL            ;Write over char
  1044.         MOV    AL,SPACE        ; with space
  1045.         MOV    AH,NCLR            ;Normal color
  1046.         CALL    CRT_CHAR        ;Do it
  1047.         JMP    BUF_1
  1048. BUF_ESC:
  1049.         OR    CX,CX            ;If chars in buf
  1050.         JNZ    BUF_ERASE        ;Erase them all
  1051.         STC                ;Carry means we're backing out
  1052.         JMP    SHORT BUF_RET
  1053. BUF_CR:
  1054.         OR    CX,CX            ;If no chars
  1055.         JZ    BUF_OK            ; simply return
  1056.         SHR    CX,1            ;Number of words to transfer
  1057.         MOV    SI,OFFSET INKEY_BUF
  1058.         CLD
  1059. BUF_LOOP:
  1060.         LODSW
  1061.         CALL    SAVE_KEY
  1062.         LOOP    BUF_LOOP
  1063. BUF_OK:
  1064.         CLC
  1065. BUF_RET:
  1066.         POP    SI            ;Restore regs
  1067.         POP    CX
  1068.         POP    AX
  1069.         RET
  1070.  
  1071. BUFFERED_INPUT    ENDP
  1072.  
  1073. ;======================================================================
  1074. ;  Beep at the terminal.
  1075. ;----------------------------------------------------------------------
  1076. BEEP        PROC    NEAR
  1077.  
  1078.         PUSH    AX            ;Save register
  1079.         MOV    AX,0E07H        ;write a 'beel'
  1080.         CALL    VIDEO            ; Thru BIOS
  1081.         POP    AX            ;Restore
  1082.         RET
  1083.  
  1084. BEEP        ENDP
  1085.  
  1086. ;======================================================================
  1087. ;  Hook the necessary interrupts to avoid a collision.  Read command line
  1088. ;  Parameters.  Terminate and Stay Resident (TSR).
  1089. ;----------------------------------------------------------------------
  1090. GREEDY_MSG    DB    "/n Too Big$"
  1091. BIG_FILE    DB    "File Too Big$"
  1092. BAD_FILE_MSG    DB    "Error Opening File$"
  1093. USAGE_MSG    DB    "Usage: SLASHBAR [path]menuname.ext [/n]$"
  1094.  
  1095. INITIALIZE    PROC    NEAR
  1096.         ASSUME    CS:CSEG, DS:CSEG, ES:CSEG, SS:CSEG
  1097.  
  1098.         MOV    DX,OFFSET COPYRIGHT    ;Say who we are
  1099.         MOV    AH,9            ;Display string function
  1100.         INT    21H            ;Thru DOS
  1101.  
  1102.         CALL    CHECK_VERSION        ;Version 2.0+ or don't return
  1103.  
  1104. ;----------------------------------------------------------------------
  1105. ;  Check if already loaded in memory.  Don't load multiple copies.
  1106. ;  When this routine ends, ES points to usable copy in memory.  It may
  1107. ;  not be the same as CS.
  1108. ;----------------------------------------------------------------------
  1109.         MOV    WORD PTR [ENTPT+0],0    ;Modify to avoid false match
  1110.         MOV    WORD PTR [ENTPT+2],0
  1111.  
  1112.         XOR    BX,BX            ;BX = segment to compare
  1113.         MOV    AX,CS            ;AX = our segment
  1114. NEXT_PARA:
  1115.         INC    BX            ;Next paragraph
  1116.         MOV    ES,BX            ;Set search segment
  1117.         CMP    AX,BX            ;If current paragraph...
  1118.         JE    END_SEARCH        ;...stop
  1119.         MOV    SI,OFFSET ENTPT        ;String to compare
  1120.         MOV    DI,SI            ;Offset is same
  1121.         MOV    CX,16            ;Compare first 16 words
  1122.         REP    CMPSW            ;CMP DS:SI TO ES:DI
  1123.         OR    CX,CX            ;All matched?
  1124.         JNZ    NEXT_PARA        ;No, continue search
  1125.         JMP    SHORT SIZE_OK        ;Found a copy at ES
  1126.  
  1127. ;----------------------------------------------------------------------
  1128. ;  Didn't find a copy in memory.  Look for memory size switch.
  1129. ;----------------------------------------------------------------------
  1130. END_SEARCH:
  1131.         MOV    DI,80H            ;# chars on command line
  1132.         MOV    CL,[DI]            ; in CL
  1133.         XOR    CH,CH            ;CH = 0
  1134.         INC    DI            ;Point to 1st char
  1135.         MOV    AL,'/'            ;Look for slash
  1136.         REPNE    SCASB            ;Do it for CX chars
  1137.         JCXZ    SIZE_OK            ;No switch on line
  1138.  
  1139.         MOV    SI,DI            ;Point SI to n parameter
  1140.         DEC    DI            ;Make sure any file name
  1141.         MOV    BYTE PTR [DI],CR    ; has return after it
  1142.         MOV    DI,10            ;Base 10 (decimal)
  1143.         MOV    CX,5            ;Maximum 5 digits
  1144.         XOR    BX,BX            ;Size in BX
  1145. GET_MEM_SIZE:
  1146.         LODSB                ;Get digit
  1147.         SUB    AL,30H            ;ASCII to digit
  1148.         CMP    AL,9            ;Must be 0-9
  1149.         JA    SAVE_SIZE        ; else, end of num
  1150.         XCHG    AX,BX            ;Put digit in BX
  1151.         MUL    DI            ;Multiply sum x 10
  1152.         XOR    BH,BH            ;Make BX single digit
  1153.         ADD    BX,AX            ;Sum in BX
  1154.         LOOP    GET_MEM_SIZE        ;Continue
  1155. SAVE_SIZE:
  1156.         MOV    DTA_SIZE,BX        ;Place in variable
  1157.         XOR    AX,AX            ;Check 64 K limit
  1158.         DEC    AX
  1159.         SUB    AX,BX
  1160.         CMP    AX,OFFSET LAST_BYTE
  1161.         JA    SIZE_OK
  1162.         MOV    DX,OFFSET GREEDY_MSG
  1163. ERROR_EXIT:
  1164.         MOV    AH,9            ;Display string fn
  1165.         INT    21H            ; Thru DOS
  1166.         MOV    AX,4C01H        ;Terminate with error=1
  1167.         INT    21H            ; Thru DOS
  1168. SIZE_OK:
  1169. ;----------------------------------------------------------------------
  1170. ;  Read the command line for a path/file spec.
  1171. ;  ES may point to the resident copy!
  1172. ;----------------------------------------------------------------------
  1173.         MOV    SI,81H            ;Command line in PSP
  1174. FIND_START:
  1175.         LODSB                ;Get char
  1176.         CMP    AL,SPACE        ;If a space
  1177.         JE    FIND_START        ; skip to next char
  1178.         CMP    AL,CR            ;If NOT CR
  1179.         JNE    HAVE_START        ; found start of spec
  1180.         MOV    DX,OFFSET USAGE_MSG    ;CR = error, no file name
  1181.         JMP    ERROR_EXIT
  1182. HAVE_START:
  1183.         MOV    DX,SI
  1184.         DEC    DX            ;Name starts here
  1185. FIND_END:
  1186.         LODSB                ;Get char
  1187.         CMP    AL,SPACE        ;A space
  1188.         JE    NAME_OK
  1189.         CMP    AL,CR            ;or CR ends name
  1190.         JNE    FIND_END
  1191. NAME_OK:
  1192.         DEC    SI            ;Back up 1 char
  1193.         MOV    BYTE PTR [SI],0        ; make ASCIIZ
  1194.         MOV    AX,3D00H        ;Open for reading
  1195.         INT    21H            ; Thru DOS
  1196.         JNC    OPEN_OK
  1197. FILE_ERR:
  1198.         MOV    DX,OFFSET BAD_FILE_MSG
  1199.         JMP    ERROR_EXIT
  1200. OPEN_OK:
  1201.         MOV    BX,AX            ;Save handle in BX
  1202.         MOV    AX,4202H        ;Move file pointer
  1203.         XOR    CX,CX            ; 0 bytes from end
  1204.         XOR    DX,DX
  1205.         INT    21H            ; Thru DOS
  1206.         JC    FILE_ERR
  1207.  
  1208.         CMP    AX,ES:DTA_SIZE        ;AX has # bytes in file
  1209.         JBE    FILE_FINE        ;Size OK
  1210.         MOV    DX,OFFSET BIG_FILE
  1211.         JMP    ERROR_EXIT
  1212. FILE_FINE:
  1213.         PUSH    AX            ;Number of bytes to read
  1214.         MOV    AX,4200H        ;Move file pointer
  1215.         XOR    CX,CX            ; 0 bytes from start
  1216.         XOR    DX,DX
  1217.         INT    21H            ; Thru DOS
  1218.         POP    CX
  1219.         JC    FILE_ERR
  1220.  
  1221.         MOV    AH,3FH            ;Read file fn
  1222.         MOV    DX,OFFSET FILE_DTA    ;Put data at this offset
  1223.         PUSH    DS            ;(Save DS)
  1224.         PUSH    ES            ;Put ES (resident segment)
  1225.         POP    DS            ; into DS (DS:DX is DTA)
  1226.         INT    21H            ;Thru DOS
  1227.         POP    DS            ;Restore old DS
  1228.         JC    FILE_ERR
  1229.  
  1230.         MOV    AH,3EH            ;Close file Fn
  1231.         INT    21H            ; Thru DOS
  1232.  
  1233.         MOV    CX,CS            ;Check if ES=CS, i.e.,
  1234.         MOV    BX,ES            ;there is no resident copy
  1235.         CMP    CX,BX
  1236.         JE    KEEP
  1237.  
  1238.         MOV    AX,4C00H
  1239.         INT    21H
  1240. KEEP:
  1241. ;----------------------------------------------------------------------
  1242. ;  Get a pointer to the DOS Critical Flag, a one-byte location in low memory
  1243. ;  that is set when DOS is in an uninterruptable state.  Location is returned
  1244. ;  in ES:BX.  This is undocumented, but works in DOS 2.0 - 3.21
  1245. ;----------------------------------------------------------------------
  1246.         PUSH    ES
  1247.         MOV    AH,34H            ;Get Interrupt Flag address
  1248.         INT    21H
  1249.  
  1250.         MOV    WORD PTR DOS_FLAG[0],BX    ;offset
  1251.         MOV    WORD PTR DOS_FLAG[2],ES    ;segment
  1252.         POP    ES
  1253.  
  1254. ;----------------------------------------------------------------------
  1255. ;  Hook the keyboard interrupt 9h for the hot-key detection routine.
  1256. ;  Hook Int 16h for BIOS keyboard control.
  1257. ;  Hook DOS Interrupt 21h,25h,26h and BIOS 13h to set busy flags.
  1258. ;----------------------------------------------------------------------
  1259.         MOV    AL,9            ;Interrupt number
  1260.         MOV    DI,OFFSET OLD_INT_9    ;Store vector here
  1261.         MOV    DX,OFFSET INT_9        ;New interrupt procedure
  1262.         CALL    SET_INT            ;Make change
  1263.  
  1264.         MOV    AL,16H
  1265.         MOV    DI,OFFSET OLD_INT_16
  1266.         MOV    DX,OFFSET INT_16
  1267.         CALL    SET_INT
  1268.  
  1269.         MOV    AL,21H
  1270.         MOV    DI,OFFSET OLD_INT_21
  1271.         MOV    DX,OFFSET INT_21
  1272.         CALL    SET_INT
  1273.  
  1274. ;----------------------------------------------------------------------
  1275. ;  Deallocate the copy of the environment loaded with the program.
  1276. ;  Establish memory residency and terminate.
  1277. ;----------------------------------------------------------------------
  1278.         MOV    AX,WORD PTR DS:[2CH]    ;Address of environment
  1279.         MOV    ES,AX            ;In ES register
  1280.         MOV    AH,49H            ;Release allocated memory
  1281.         INT    21H            ;Thru DOS
  1282.  
  1283.         MOV    DX,OFFSET LAST_BYTE - OFFSET CSEG + 15
  1284.         ADD    DX,DTA_SIZE        ;Total size in bytes
  1285.         MOV    CL,4            ; /16 =
  1286.         SHR    DX,CL            ;In paras
  1287.         MOV    AX,3100H        ;Keep (TSR)
  1288.         INT    21H            ;Thru DOS
  1289.  
  1290. INITIALIZE    ENDP
  1291.  
  1292. ;======================================================================
  1293. ;  Check for the correct version of DOS.  Return if 2.0 or later.
  1294. ;  Terminate if 1.x.  AX destroyed on return.
  1295. ;----------------------------------------------------------------------
  1296. BAD_DOS_MSG    DB    "SlashBar: Requires DOS 2.0+",CR,LF,"$"
  1297.  
  1298. CHECK_VERSION    PROC    NEAR
  1299.         ASSUME    CS:CSEG, DS:CSEG, ES:CSEG, SS:CSEG
  1300.  
  1301.         MOV    AH,30H            ;Get DOS version number    fn
  1302.         INT    21H            ;Thru DOS
  1303.                         ;AL=major ver #,AH=minor ver #
  1304.         CMP    AL,02            ;Compare to 2.0
  1305.         JAE    VER_OK            ;If 2.0 or later, go on.
  1306.  
  1307.         MOV    DX,OFFSET BAD_DOS_MSG    ;DS:DX is message
  1308.         MOV    AH,9            ;Display string fn
  1309.         INT    21H            ;Thru DOS
  1310.         INT    20H            ;Exit 1.0 style
  1311. VER_OK:
  1312.         RET
  1313.  
  1314. CHECK_VERSION    ENDP
  1315.  
  1316. ;======================================================================
  1317. ;  Get/Save/Set the interrupt vector.  AL contains vector number.
  1318. ;  ES:DI points to DWORD destination for old address.
  1319. ;  DS:DX points to new interrupt address.  AX destroyed.
  1320. ;----------------------------------------------------------------------
  1321. SET_INT        PROC    NEAR
  1322.         ASSUME    CS:CSEG, DS:CSEG, ES:CSEG, SS:CSEG
  1323.  
  1324.         PUSH    ES
  1325.         PUSH    AX            ;Save vector # in AL
  1326.         MOV    AH,35H            ;Get address function
  1327.         INT    21H            ;Thru DOS
  1328.         MOV    WORD PTR [DI+0],BX    ;Save address in ES:DI
  1329.         MOV    WORD PTR [DI+2],ES
  1330.         POP    AX            ;Get AL back
  1331.         MOV    AH,25H            ;Set new address to DS:DX
  1332.         INT    21H            ;Thru DOS
  1333.         POP    ES
  1334.         RET
  1335.  
  1336. SET_INT        ENDP
  1337.  
  1338. ;======================================================================
  1339. ;  Data here is allocated after the program loads into memory to save space
  1340. ;  in the COM file so the basic listing will be smaller.
  1341. ;  PC variable used to keep track of relative addresses.
  1342. ;----------------------------------------------------------------------
  1343. PC        =    $            ;Set imaginary counter
  1344.  
  1345. SCREEN_BUF    =    PC            ;DB NROW*NCOL*2 DUP(?)
  1346. PC        =    PC + NROW * NCOL * 2
  1347.  
  1348. KEYS        =    PC            ;DW 256 DUP(0)
  1349. PC        =    PC + 256 * 2
  1350.                         ;For buffered input
  1351. INKEY_BUF    =    PC            ;DW 76 DUP(0)
  1352. PC        =    PC + 76 * 2
  1353.  
  1354. KEY_STK        =    PC            ;DW 32 DUP(0)
  1355. PC        =    PC + 32 * 2
  1356.  
  1357. MENU_STK    =    PC            ;DW 32 DUP(0)
  1358. PC        =    PC + 32 * 2
  1359.  
  1360. FILE_DTA    =    PC
  1361. LAST_BYTE    =    PC
  1362.  
  1363. CSEG    ENDS
  1364.     END    ENTPT
  1365.